#include <iostream>
#include <opencv2/opencv.hpp>

int c, num;

// 黑色识别
cv::Mat black_discern(cv::Mat img)
{
    cv::Mat hsv, mask, res;
    cvtColor(img, hsv, cv::COLOR_BGR2HSV);  // BGR转换成HSV
    inRange(hsv, cv::Scalar(0, 0, 0), cv::Scalar(0, 0, 0), mask);
    bitwise_and(img, img, res, mask = mask);
    return res;
}

// 轮廓检测以及面积测定
int calculate_area(cv::Mat img_color, int thresh)
{
    cv::Mat dst2, edges, gray;
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));  // 形态学运算核
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;

    cvtColor(img_color, gray, cv::COLOR_BGR2GRAY);  // 灰度图，BGR转GRAY
    GaussianBlur(gray, gray, cv::Size(3, 3), 3, 0); // 高斯滤波去噪

    adaptiveThreshold(gray, edges, 254, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 21, 3); // 自适应二值化
    dilate(edges, dst2, kernel, cv::Point(-1, -1), 4);  // 膨胀连接断线
    findContours(dst2, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); //寻找轮廓


    for (int obj = 0; obj < contours.size(); obj++) {
        double area = fabs(contourArea(contours[obj]));  // 求轮廓面积
        if (area > thresh) {
            drawContours(img_color, contours, -1, cv::Scalar(255, 0, 0), 2); //绘制轮廓
            cv::Rect rect = boundingRect(contours[obj]);
            rectangle(img_color, rect, cv::Scalar(0, 255, 0), 2); // 对目标物绘制矩形
            putText(img_color, std::to_string(area), cv::Point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)),
                cv::FONT_HERSHEY_COMPLEX, 0.6, cv::Scalar(0, 255, 0), 2);
            c++;
        }
    }
    return 0;
}

int main() {
    cv::VideoCapture cap(1); //打开摄像头
    // 判断摄像头是否打开
    if (int test = !cap.isOpened()) {
        std::cout << "fail to open";
        return -1;
    }
    while (true) {
        cv::Mat img_org, img_black;
        cap.read(img_org);

        img_black = black_discern(img_org);       // 调用颜色识别函数
        int black = calculate_area(img_black, 0); // 调用轮廓检测函数

        imshow("img_black", img_black);             //显示图片
        imshow("img", img_org);

        num++;
        if (num == 5)
        {
            std::cout << "金矿数量：" << c << std::endl;
            num = 0;
        }
        c = 0;
        // 等待按键
        if (cv::waitKey(1) == 27)                    
            break;
    }
    return 0;
}